package com.sz.biz.common.customer.service.impl;

import com.sz.biz.common.base.dto.AreaDto;
import com.sz.biz.common.base.service.AreaService;
import com.sz.biz.common.constants.CommCodes;
import com.sz.biz.common.constants.ErrorCodes;
import com.sz.biz.common.constants.LanguageCode;
import com.sz.biz.common.constants.TransportConstants;
import com.sz.biz.common.customer.dto.CusUserAddressDto;
import com.sz.biz.common.customer.entity.AddressTypeEnum;
import com.sz.biz.common.customer.entity.CusUserAddress;
import com.sz.biz.common.customer.service.CustomerUserAddressService;
import com.sz.biz.logistics.base.dto.AirportDto;
import com.sz.biz.logistics.base.dto.PortDto;
import com.sz.biz.logistics.base.service.AirportService;
import com.sz.biz.logistics.base.service.PortService;
import com.sz.biz.logistics.core.dto.ProductAddressDto;
import com.sz.biz.logistics.core.entity.ProductGroup;
import com.sz.biz.logistics.core.service.ProductGroupService;
import com.sz.biz.logistics.core.service.ProductService;
import com.sz.common.base.dao.DaoSupport;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.core.service.PrincipalUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("CustomerUserAddressService")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class CustomerUserAddressServiceImpl implements CustomerUserAddressService {

    private static final int MAX_COUNT = 10;
    @Resource(name = "daoSupport")
    private DaoSupport dao;

    @Autowired
    private AreaService areaService;
    @Autowired
    private AirportService airportService;
    @Autowired
    private PortService portService;
    @Autowired
    private ProductGroupService productGroupService;
    @Autowired
    private ProductService productService;

    @Override
    public int saveOrUpdate(CusUserAddressDto addressDto) {
        int result = 0;
        checkDataValid(addressDto);
        CusUserAddress cusUserAddress = new CusUserAddress();
        BeanUtils.copyProperties(addressDto, cusUserAddress);
        int transportType = productGroupService.findTypeById(addressDto.getTransportType());
        cusUserAddress.setTransportType(transportType);
        if (transportType == TransportConstants.Type.AIR ) {
            AirportDto airportDto = airportService.findByAirportId(cusUserAddress.getTransportId());
            AreaDto areaDto;
            if (LanguageCode.CN_UPPER.equalsIgnoreCase(airportDto.getCountryId())) {
                areaDto = areaService.findByAreaId(airportDto.getCityId(), airportDto.getCountryId());
                if (!ObjectUtils.isEmpty(areaDto)) {
                    cusUserAddress.setProvince(areaDto.getParentId());
                }
            }
            if (airportDto != null) {
                cusUserAddress.setCity(airportDto.getCityId());
                cusUserAddress.setCountry(airportDto.getCountryId());
                cusUserAddress.setAddress(airportDto.getAddress());

            }
        } else if (transportType == 1) {
            PortDto portDto = portService.findByPortId(cusUserAddress.getTransportId());
            AreaDto areaDto;
            if (portDto != null && LanguageCode.CN_UPPER.equalsIgnoreCase(portDto.getCountryId())) {
                areaDto = areaService.findByAreaId(portDto.getCityId(), portDto.getCountryId());
                if (!ObjectUtils.isEmpty(areaDto)) {
                    cusUserAddress.setProvince(areaDto.getParentId());
                }
            }
            if (portDto != null) {
                cusUserAddress.setCity(portDto.getCityId());
                cusUserAddress.setCountry(portDto.getCountryId());
                cusUserAddress.setAddress(portDto.getAddress());
            }
        } else {
            cusUserAddress.setDistrict(addressDto.getDistrictId());
            cusUserAddress.setCity(addressDto.getCityId());
            cusUserAddress.setCountry(addressDto.getCountryCode());
            cusUserAddress.setProvince(addressDto.getProvinceId());
            cusUserAddress.setStreet(addressDto.getStreetId());
        }
        if (addressDto.getId() != null && addressDto.getId() > 0) {
            cusUserAddress.setLastUpdateUserId(PrincipalUtils.getAccountId());
            result = (int) dao.update("CusUserAddressMapper.updateAllDataById", cusUserAddress);
        } else {
            int count = queryCountByCustomerIdAndType(cusUserAddress.getCustomerId(), cusUserAddress.getType(), cusUserAddress.getTransportType());
            if (count >= MAX_COUNT) {
                if (cusUserAddress.getType() == AddressTypeEnum.SENDADDRESS.getCode()) {
                    if (cusUserAddress.getTransportType() == TransportConstants.Type.AIR) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_CUSTOMER_USER_SEND_AIR_ADDRESS_MAX);
                    }
                    if (cusUserAddress.getTransportType() == TransportConstants.Type.SEA ) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_CUSTOMER_USER_SEND_SEA_ADDRESS_MAX);
                    }
                    if (cusUserAddress.getTransportType() == TransportConstants.Type.LAND) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_CUSTOMER_USER_SEND_EXPRESS_ADDRESS_MAX);
                    }
                } else if (cusUserAddress.getType() == AddressTypeEnum.RECEIVERADDRESS.getCode()) {

                    if (cusUserAddress.getTransportType() == TransportConstants.Type.AIR) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_CUSTOMER_USER_RECEIVE_AIR_ADDRESS_MAX);
                    }
                    if (cusUserAddress.getTransportType() == TransportConstants.Type.SEA) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_CUSTOMER_USER_RECEIVE_SEA_ADDRESS_MAX);
                    }
                    if (cusUserAddress.getTransportType() == TransportConstants.Type.LAND) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_CUSTOMER_USER_RECEIVE_EXPRESS_ADDRESS_MAX);
                    }
                } else {
                    throw Exceptions.bizException(ErrorCodes.ERROR_CUSTOMER_USER_PICK_ADDRESS_MAX);
                }
            }
            cusUserAddress.setLastUpdateUserId(PrincipalUtils.getAccountId());
            cusUserAddress.setCreateUserId(PrincipalUtils.getAccountId());
            result = (int) dao.save("CusUserAddressMapper.insertSelective", cusUserAddress);
            if (result != 0) {
                return cusUserAddress.getId();
            }
        }
        return result;
    }

    private void checkDataValid(CusUserAddressDto addressDto) {
        if (addressDto != null) {
            if (addressDto.getTransportType() != TransportConstants.Type.SEA && addressDto.getTransportType() != TransportConstants.Type.AIR) {
                if (addressDto.getCustomerId() == null || addressDto.getCustomerId() == 0) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "CustomerId");
                }
                if (addressDto.getType() == null || (addressDto.getType() != AddressTypeEnum.SENDADDRESS.getCode()
                        && addressDto.getType() != AddressTypeEnum.PICKADDRESS.getCode())
                        && addressDto.getType() != AddressTypeEnum.RECEIVERADDRESS.getCode()) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "type");
                }
                if (StringUtils.isEmpty(addressDto.getPostcode())) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "postcode");
                }
                if (StringUtils.isEmpty(addressDto.getCountryCode())) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "countryCode");
                }
                if (StringUtils.isEmpty(addressDto.getAddress())) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "address");
                }
                if (LanguageCode.CN_LOWER.equals(addressDto.getCountryCode().toLowerCase())) {
                    if (StringUtils.isEmpty(addressDto.getProvinceId())) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "ProvinceId");
                    }
                    if (StringUtils.isEmpty(addressDto.getCityId())) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "CityId");
                    }
                } else {
                    if (StringUtils.isEmpty(addressDto.getCityId())) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "CityId");
                    }
                }
            } else {
                if (addressDto.getCustomerId() == null || addressDto.getCustomerId() == 0) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "CustomerId");
                }
                if (addressDto.getType() == null || (addressDto.getType() != AddressTypeEnum.SENDADDRESS.getCode()
                        && addressDto.getType() != AddressTypeEnum.PICKADDRESS.getCode())
                        && addressDto.getType() != AddressTypeEnum.RECEIVERADDRESS.getCode()) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "type");
                }

                if (addressDto.getTransportId() == null || addressDto.getTransportId() == 0) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "transportId");
                }
            }
            if (addressDto.getIsDefault() == null) {
                addressDto.setIsDefault(false);
            }
            if (StringUtils.isEmpty(addressDto.getTelPhone()) && StringUtils.isEmpty(addressDto.getPhone())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "telPhone or phone");
            }
        }
    }

    @Override
    public void delete(List<Integer> ids, int customerId) {
        if (ids == null || ids.size() == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "ids");
        }
        if (customerId == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "customerId");
        }
        List<Map<String, Integer>> deleteIds = new ArrayList<>();
        for (int id : ids) {
            Map<String, Integer> deleteMap = new HashMap<>();
            deleteMap.put("id", id);
            deleteMap.put("customerId", customerId);
            deleteIds.add(deleteMap);
        }
        dao.batchDelete("CusUserAddressMapper.deleteByPrimaryKeyAndCustomerId", deleteIds);
    }

    @Override
    public CusUserAddress findById(int id) {
        CusUserAddress cusUserAddress = (CusUserAddress) dao.findForObject("CusUserAddressMapper.selectByPrimaryKey", id);
        return cusUserAddress;
    }

    @Override
    public List<CusUserAddressDto> queryByCusIdAndIdsAndType(Integer id, Integer customerId, Integer type, Integer transportType) {

        if (customerId == null || customerId == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "customerId");
        }
        if (type == null
                || (type != AddressTypeEnum.SENDADDRESS.getCode() && type != AddressTypeEnum.PICKADDRESS.getCode()
                && type != AddressTypeEnum.RECEIVERADDRESS.getCode())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "type");
        }
        Map<String, Object> param = new HashMap<>();
        if (id != null && id > 0) {
            param.put("id", id);
        }
        if (transportType != null && transportType > 0) {
            param.put("transportType", transportType);
        }
        param.put("type", type);
        param.put("customerId", customerId);
        List<CusUserAddress> cusUserAddressList = dao.findForList("CusUserAddressMapper.selectByidsAndCusUserIdAndType",
                param, CusUserAddress.class);
        return buildQueryResult(cusUserAddressList);
    }

    @Override
    public void setDefault(Integer oldId, Integer newId, Integer customerId, Integer type, Integer transportType) {
        if (newId == null || newId == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "newId");
        }
        if (customerId == null || customerId == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "customerId");
        }
        if (type == null
                || (type != AddressTypeEnum.SENDADDRESS.getCode() && type != AddressTypeEnum.PICKADDRESS.getCode()
                && type != AddressTypeEnum.RECEIVERADDRESS.getCode())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "type");
        }
        if (transportType != null
                && (transportType != 6 && transportType != 1 && transportType != 11)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "transportType");
        }

        if (oldId != null) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", oldId);
            map.put("customerId", customerId);
            map.put("isDefault", false);
            map.put("type", type);
            map.put("transportType", transportType);
            dao.update("CusUserAddressMapper.updateIsDefault", map);
        } else {
            List<CusUserAddress> cusUserAddressList = dao.findForList("CusUserAddressMapper.queryDefaultAddress",
                    customerId, CusUserAddress.class);
            if (cusUserAddressList != null && cusUserAddressList.size() > 0) {
                for (CusUserAddress cusUserAddress : cusUserAddressList) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("id", cusUserAddress.getId());
                    map.put("customerId", customerId);
                    map.put("isDefault", false);
                    map.put("type", type);
                    map.put("transportType", transportType);
                    dao.update("CusUserAddressMapper.updateIsDefault", map);
                }
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("id", newId);
        map.put("customerId", customerId);
        map.put("isDefault", true);
        map.put("type", type);
        map.put("transportType", transportType);
        dao.update("CusUserAddressMapper.updateIsDefault", map);
    }

    @Override
    public int queryCountByCustomerIdAndType(Integer customerId, Integer type, Integer transportType) {
        if (customerId == null || customerId == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "customerId");
        }
        if (type != null
                && (type != AddressTypeEnum.SENDADDRESS.getCode() && type != AddressTypeEnum.PICKADDRESS.getCode()
                && type != AddressTypeEnum.RECEIVERADDRESS.getCode())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "type");
        }

        if (transportType != null
                && (transportType != 6 && transportType != 1 && transportType != 11)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "transportType");
        }

        ParamData pd = new ParamData();
        pd.put("customerId", customerId);
        if (type != null) {
            pd.put("type", type);
        }
        if (transportType != null) {
            pd.put("transportType", transportType);
        }
        int count = (Integer) dao.findForObject("CusUserAddressMapper.findCountByCustomerIdAndType", pd);

        return count;
    }

    @Override
    public List<CusUserAddress> findCountryByCustomerIdAndType(Integer customerId, Integer type) {
        if (customerId == null || customerId == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "customerId");
        }
        if (type != null
                && (type != AddressTypeEnum.SENDADDRESS.getCode() && type != AddressTypeEnum.PICKADDRESS.getCode()
                && type != AddressTypeEnum.RECEIVERADDRESS.getCode())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "type");
        }
        ParamData pd = new ParamData();
        pd.put("customerId", customerId);
        if (type != null) {
            pd.put("type", type);
        }
        List<CusUserAddress> cusUserAddressList = dao.findForList("CusUserAddressMapper.findCountryByCustomerIdAndType",
                pd, CusUserAddress.class);

        return cusUserAddressList;
    }

    /**
     * 根据服务，筛选出可用地址和不可用地址
     *
     * @param customerId
     * @param type          1、发货地址 2、收货地址,3揽收地址
     * @param transportType 全球海运:1,全球速递:11,全球空运:6
     * @param uid
     * @return
     */
    @Override
    public Map<String, List<CusUserAddressDto>> findAddressByProduct(Integer customerId, Integer type, Integer transportType, String uid) {

        if (transportType != null
                && (transportType != 6 && transportType != 1 && transportType != 11)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_NOT_EXIST, "transportType");
        }
        Map<String, List<CusUserAddressDto>> result = new HashMap();
        String addressType = "";
        if (type!=null && type == AddressTypeEnum.SENDADDRESS.getCode()) {
            addressType = CommCodes.PRODUCT_SERVICE_REGION_START;
        } else if (type!=null && type == AddressTypeEnum.RECEIVERADDRESS.getCode()) {
            addressType =  CommCodes.PRODUCT_SERVICE_REGION_END;
        } else if (type!=null && type == AddressTypeEnum.PICKADDRESS.getCode()) {
            addressType = CommCodes.PRODUCT_SERVICE_REGION_PICKUP;
        }


        //发件人地址
        if (CommCodes.PRODUCT_SERVICE_REGION_START.equals(addressType) || StringUtils.isEmpty(addressType)) {
            List<ProductAddressDto> addressDtoList = productService.getProductAddress(uid, CommCodes.PRODUCT_SERVICE_REGION_START);
            List<CusUserAddressDto> cusUserAddressDtoList = this.queryByCusIdAndIdsAndType(0, customerId, 1, transportType);
            for (CusUserAddressDto addressDto : cusUserAddressDtoList) {
                ProductAddressDto productAddressDto = productService.getProductAddressDto(transportType, addressDto);
                boolean bOk = productService.checkProductAddress(addressDtoList, productAddressDto);
                addressDto.setEnable(bOk);
            }
            result.put("send", cusUserAddressDtoList);
        }
        if (CommCodes.PRODUCT_SERVICE_REGION_END.equals(addressType) || StringUtils.isEmpty(addressType)) {
            List<ProductAddressDto> addressDtoList = productService.getProductAddress(uid, CommCodes.PRODUCT_SERVICE_REGION_END);
            List<CusUserAddressDto> cusUserAddressDtoList = this.queryByCusIdAndIdsAndType(0, customerId, 2, transportType);
            for (CusUserAddressDto addressDto : cusUserAddressDtoList) {
                ProductAddressDto productAddressDto = productService.getProductAddressDto(transportType, addressDto);
                boolean bOk = productService.checkProductAddress(addressDtoList, productAddressDto);
                addressDto.setEnable(bOk);
            }
            result.put("receiver", cusUserAddressDtoList);
        }
        if (CommCodes.PRODUCT_SERVICE_REGION_PICKUP.equals(addressType) || StringUtils.isEmpty(addressType)) {
            List<ProductAddressDto> addressDtoList = productService.getProductAddress(uid, CommCodes.PRODUCT_SERVICE_REGION_PICKUP);
            List<CusUserAddressDto> cusUserAddressDtoList = this.queryByCusIdAndIdsAndType(0, customerId, 3, 11);
            for (CusUserAddressDto addressDto : cusUserAddressDtoList) {
                ProductAddressDto productAddressDto = productService.getProductAddressDto(transportType, addressDto);
                boolean bOk = productService.checkProductAddress(addressDtoList, productAddressDto);
                addressDto.setEnable(bOk);
            }
            result.put("pick", cusUserAddressDtoList);
        }
        return result;
    }

    @Override
    public List<CusUserAddressDto> queryByCusIdAndtransportType(Integer customerId, Integer transportType) {
        if (customerId == null || customerId == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "customerId");
        }
        Map<String, Object> param = new HashMap<>();
        if (transportType != null && transportType > 0) {
            param.put("transportType", transportType);
        }
        param.put("customerId", customerId);
        List<CusUserAddress> cusUserAddressList = dao.findForList("CusUserAddressMapper.selectByidsAndCusUserIdAndType",
                param, CusUserAddress.class);
        return buildQueryResult(cusUserAddressList);
    }

    private List<CusUserAddressDto> buildQueryResult(List<CusUserAddress> cusUserAddressList) {
        List<CusUserAddressDto> cusUserAddressDtos = new ArrayList<>();
        for (CusUserAddress cusUserAddress : cusUserAddressList) {
            CusUserAddressDto cusUserAddressDto = new CusUserAddressDto();
            BeanUtils.copyProperties(cusUserAddress, cusUserAddressDto);
            cusUserAddressDto.setCountryCode(cusUserAddress.getCountry());
            cusUserAddressDto.setProvinceId(cusUserAddress.getProvince());
            cusUserAddressDto.setCityId(cusUserAddress.getCity());
            ProductGroup productGroup = productGroupService.findById(cusUserAddress.getTransportType());
            if (cusUserAddress.getTransportType() == 6) {
                AirportDto airportDto = airportService.findByAirportId(cusUserAddress.getTransportId());
                if (airportDto != null) {
                    cusUserAddressDto.setCityName(airportDto.getCityName());
                    cusUserAddressDto.setCountryName(airportDto.getCountryName());
                    cusUserAddressDto.setTransportName(airportDto.getName());
                    cusUserAddressDto.setTransportCode(airportDto.getTriadCode());
                    if (productGroup != null) {
                        cusUserAddressDto.setTransportTypeName(productGroup.getName());
                    }
                    cusUserAddressDtos.add(cusUserAddressDto);
                }
            } else if (cusUserAddress.getTransportType() == 1) {
                PortDto portDto = portService.findByPortId(cusUserAddress.getTransportId());
                if (portDto != null) {
                    cusUserAddressDto.setCityName(portDto.getCityName());
                    cusUserAddressDto.setCountryName(portDto.getCountryName());
                    cusUserAddressDto.setTransportName(portDto.getName());
                    cusUserAddressDto.setTransportCode(portDto.getCode());
                    cusUserAddressDto.setTransportEnglishName(portDto.getEnglishName());
                    cusUserAddressDto.setAddress(portDto.getAddress());
                    if (productGroup != null) {
                        cusUserAddressDto.setTransportTypeName(productGroup.getName());
                    }
                    cusUserAddressDtos.add(cusUserAddressDto);
                }
            } else {
                //customerUserAddress.findById(airport.get)
                cusUserAddressDto.setCityId(cusUserAddress.getCity());
                cusUserAddressDto.setCountryCode(cusUserAddress.getCountry());
                cusUserAddressDto.setStreetId(cusUserAddress.getStreet());
                cusUserAddressDto.setDistrictId(cusUserAddress.getDistrict());
                cusUserAddressDto.setProvinceId(cusUserAddress.getProvince());
                if (productGroup != null) {
                    cusUserAddressDto.setTransportTypeName(productGroup.getName());
                }
                areaService.setAddressModel(cusUserAddressDto);
                cusUserAddressDtos.add(cusUserAddressDto);
            }

        }
        return cusUserAddressDtos;
    }
}
